/**
 * Copyright 1998-2006, CHISEL Group, University of Victoria, Victoria, BC, Canada.
 * All rights reserved.
 */
package ca.uvic.cs.cogz.mapping.core;

import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Stroke;
import java.util.Collection;

import javax.swing.JPanel;

import ca.uvic.cs.cogz.mapping.core.MappingTypeManager.MappingType;
import edu.stanford.smi.protege.model.Frame;
import edu.stanford.smi.protegex.prompt.operation.Operation;

/**
 * Abstract map element for describing a map element.
 * 
 * @author Sean Falconer
 * @date 10-Jan-07
 */
public abstract class AbstractMapElement {
	public static final AlphaComposite ALPHA_PARTIAL_TRANSPARENT = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.2f);
	public static final AlphaComposite ALPHA_OPAQUE = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1f);

	public static final Color DEFAULT_LINE_COLOR = Color.black;
	public static final Color HIGHLIGHT_LINE_COLOR = Color.blue;

	public static final int DEFAULT_LINE_THICKNESS = 3;
	public static final int THIN_LINE_THICKNESS = 1;

	public static final boolean DEFAULT_DASHED_LINE = false;
	public static final Stroke DEFAULT_STROKE = new BasicStroke(DEFAULT_LINE_THICKNESS, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);

	protected Frame targetFrame;
	protected Frame sourceFrame;

	protected Collection<Frame> sourcePath;
	protected Collection<Frame> targetPath;

	protected Operation operation;

	protected String annotation;

	protected Color color;
	protected Color selectedColor;
	protected Color highlightColor;

	protected float thickness;
	protected boolean dashed;

	protected Stroke thinStroke;
	protected Stroke thickStroke;

	protected JPanel previewPanel;

	protected boolean highlight;
	protected boolean selected;

	public Operation getOperation() {
		return operation;
	}

	public Collection<Frame> getSourcePath() {
		return sourcePath;
	}

	public void setSourcePath(Collection<Frame> sourcePath) {
		this.sourcePath = sourcePath;
	}

	public Collection<Frame> getTargetPath() {
		return targetPath;
	}

	public void setTargetPath(Collection<Frame> targetPath) {
		this.targetPath = targetPath;
	}

	public void setHightlight(boolean highlight) {
		this.highlight = highlight;
	}

	public boolean hasHighlight() {
		return highlight;
	}

	public boolean isSelected() {
		return selected;
	}

	public void setSelected(boolean selected) {
		this.selected = selected;
	}

	public boolean hasAnnotation() {
		return annotation != null && annotation.length() > 0;
	}

	public String getAnnotation() {
		return annotation;
	}

	public void setAnnotation(String annotation) {
		this.annotation = (annotation == null ? "" : annotation);
	}

	public AlphaComposite getComposite() {
		if (selected || highlight) {
			return ALPHA_OPAQUE;
		}
		return ALPHA_PARTIAL_TRANSPARENT;
	}

	public Color getLineColor() {
		if (selected) {
			return selectedColor;
		} else if (highlight) {
			return highlightColor;
		}

		return color;
	}

	public void setLineColor(Color lineColor) {
		this.color = lineColor;
		updateStrokeAndPreview();
	}

	public float getLineThickness() {
		return thickness;
	}

	public void setLineThickness(float lineThickness) {
		this.thickness = Math.max(1f, lineThickness);
		updateStrokeAndPreview();
	}

	public boolean isDashedLine() {
		return dashed;
	}

	public void setDashedLine(boolean dashed) {
		this.dashed = dashed;
		updateStrokeAndPreview();
	}

	public Stroke getStroke() {
		if (highlight || selected) {
			return thickStroke;
		}

		return thinStroke;
	}

	public Frame getTargetFrame() {
		return targetFrame;
	}

	public Frame getSourceFrame() {
		return sourceFrame;
	}

	public String toString() {
		return sourceFrame.getBrowserText() + " -> " + targetFrame.getBrowserText();
	}

	public abstract MappingType getMappingType();

	protected void updateStrokeAndPreview() {
		thinStroke = createStroke(THIN_LINE_THICKNESS, dashed);
		thickStroke = createStroke(DEFAULT_LINE_THICKNESS, dashed);
		if ((previewPanel != null) && previewPanel.isVisible()) {
			previewPanel.repaint();
		}
	}

	private static Stroke createStroke(float thickness, boolean dashed) {
		Stroke stroke;
		if (dashed) {
			stroke = new BasicStroke(thickness, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 1f, new float[] { 15f, 10f }, 0);
		} else {
			stroke = new BasicStroke(thickness, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);
		}
		return stroke;
	}
}
